package com.lkd.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.base.Strings;
import com.lkd.common.VMSystem;
import com.lkd.dao.UserDao;
import com.lkd.entity.UserEntity;
import com.lkd.exception.LogicException;
import com.lkd.feign.VmServiceFeignClient;
import com.lkd.http.controller.vo.LoginReq;
import com.lkd.http.controller.vo.LoginResp;
import com.lkd.http.view.TokenObject;
import com.lkd.service.PartnerService;
import com.lkd.service.UserService;
import com.lkd.sms.SmsSender;
import com.lkd.utils.BCrypt;
import com.lkd.utils.JWTUtil;
import com.lkd.vo.Pager;
import com.lkd.vo.UserVO;
import com.lkd.vo.VmVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserDao,UserEntity> implements UserService{
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Override
    public Integer getOperatorCount() {
        LambdaQueryWrapper<UserEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserEntity::getRoleCode,"1002");

        return this.count(wrapper);
    }

    @Override
    public Integer getRepairerCount() {
        LambdaQueryWrapper<UserEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserEntity::getRoleCode,"1003");

        return this.count(wrapper);
    }

    @Override
    public Pager<UserEntity> findPage(long pageIndex, long pageSize, String userName,Integer roleId,Boolean isRepair) {
        Page<UserEntity> page = new Page(pageIndex,pageSize);

        LambdaQueryWrapper<UserEntity> wrapper = new LambdaQueryWrapper<>();
        if(!Strings.isNullOrEmpty(userName)){
            wrapper.like(UserEntity::getUserName,userName);
        }
        if(roleId != null && roleId > 0){
            wrapper.eq(UserEntity::getRoleId,roleId);
        }
        if(isRepair != null && isRepair == true){
            wrapper.eq(UserEntity::getRoleCode,"1003");
        }
        if(isRepair != null && isRepair == false){
            wrapper.eq(UserEntity::getRoleCode,"1002");
        }
        wrapper.ne(UserEntity::getRoleId,1);
        this.page(page,wrapper);
        page.getRecords().forEach(u->{
            u.setPassword("");
            u.setSecret("");
        });

        return Pager.build(page);
    }

    @Override
    public List<UserVO> getOperatorList(Long regionId) {
        LambdaQueryWrapper<UserEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper
                .eq(UserEntity::getRoleCode,"1002")
                .eq(UserEntity::getRegionId,regionId)
                .eq(UserEntity::getStatus,true);

        return this.list(wrapper)
                .stream()
                .map(u->{
                    UserVO vo = new UserVO();
                    BeanUtils.copyProperties(u,vo);
                    vo.setRoleName(u.getRole().getRoleName());
                    vo.setRoleCode(u.getRoleCode());
                    vo.setUserId(u.getId());
                    return vo;
                }).collect(Collectors.toList());
    }

    @Override
    public List<UserVO> getRepairerList(Long regionId) {
        LambdaQueryWrapper<UserEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper
                .eq(UserEntity::getRoleCode,"1003")
                .eq(UserEntity::getRegionId,regionId)
                .eq(UserEntity::getStatus,true);

        return this.list(wrapper)
                .stream()
                .map(u->{
                    UserVO vo = new UserVO();
                    BeanUtils.copyProperties(u,vo);
                    vo.setRoleName(u.getRole().getRoleName());
                    vo.setRoleCode(u.getRoleCode());
                    vo.setUserId(u.getId());
                    return vo;
                }).collect(Collectors.toList());
    }

    @Override
    public Integer getCountByRegion(Long regionId, Boolean isRepair) {
        var qw = new LambdaQueryWrapper<UserEntity>();
        qw.eq(UserEntity::getRegionId,regionId);
        if(isRepair){
            qw.eq(UserEntity::getRoleId,3);
        }else {
            qw.eq(UserEntity::getRoleId,2);
        }

        return this.count(qw);
    }

   @Autowired
    private PartnerService partnerService;

    @Override
    public LoginResp login(LoginReq req) throws IOException {
    if(req.getLoginType() == VMSystem.LOGIN_ADMIN){
        return this.adminLogin(req);//管理员登录
    }else if(req.getLoginType() == VMSystem.LOGIN_PARTNER){
        return partnerService.login(req);
    }else if(req.getLoginType() == VMSystem.LOGIN_EMP){
        return this.appLogin(req);
    }
    LoginResp resp = new LoginResp();
    resp.setSuccess(false);
    resp.setMsg("不存在该账户");
    return resp;
   }

    /**
     * app的登录
     * @param req
     * @return
     */
    private LoginResp appLogin(LoginReq req) throws IOException {
        LoginResp resp = new LoginResp();
        resp.setSuccess(false);


        String code = req.getCode();
        String mobile = req.getMobile();
//        判断验证码是否正确
        String cacheCode = redisTemplate.opsForValue().get(mobile);
        if(!cacheCode.equals(code)){
            log.error("验证码错误");
            resp.setMsg("验证码错误");
            return resp;
        }
//        查询手机号
        LambdaQueryWrapper<UserEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(UserEntity::getMobile,mobile);
        UserEntity userEntity = getOne(queryWrapper);
        if(userEntity==null){
            log.error("用户不存在");
            resp.setMsg("用户不存在");
            return resp;
        }
//        返回生成token
        return okResp(userEntity,req.getLoginType());
    }

    @Autowired
    private SmsSender smsSender;
    /**
     * 发送短信验证码
     * @param mobile
     * @return
     */
    @Override
    public Boolean sendCode(String mobile) {
//        判断手机号是否5分钟内容发送过
        Boolean b = redisTemplate.hasKey(mobile);
        if(b){
//            验证码存在，返回
            return true;
        }
//        生成5位随机验证码
        StringBuilder stringBuilder = new StringBuilder();
        Stream.generate(()-> new Random().nextInt(10)).limit(5).forEach(x->stringBuilder.append(x));
        String code = stringBuilder.toString();
        log.info("code={}",code);
//        存入Redis中，设置有效期，5分钟
        redisTemplate.opsForValue().set(mobile,code,5, TimeUnit.MINUTES);
//        调用API发送短信
//        smsSender.sendMsg(mobile,code);
        return true;
    }

    @Autowired
    private VmServiceFeignClient vmServiceFeignClient;
    /**
     * 根据售货机编号和 是否运维 查询人员集合
     * @param innerCode
     * @param isRepair
     * @return
     */
    @Override
    public List<UserVO> getUserList(String innerCode, boolean isRepair) {

//        远程调用 售货机服务，根据售货机编号查询售货机
        VmVO vmVO = vmServiceFeignClient.getvmInfoByInnerCode(innerCode);
        if(vmVO == null){
            log.error("没有对应的售货机数据");
            throw new LogicException("没有对应的售货机数据");
        }
        Long regionId = vmVO.getRegionId();
        if(isRepair) {
            return this.getRepairerList(regionId);
        }else {
            return this.getOperatorList(regionId);
        }

    }

    /**
     * 初始化员工工单列表
     * 存入Redis 使用 zset
     */
    @Override
    public void initUserTaskList() {
        log.info("开始初始化用户工单列表");
//        查询员工列表数据。不查询role=1001 管理员
        LambdaQueryWrapper<UserEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.ne(UserEntity::getRoleCode,1001);
        List<UserEntity> userEntityList = list(queryWrapper);
        if(CollectionUtils.isEmpty(userEntityList)){
            log.error("没有查询到用户数据");
            return ;
        }

        for (UserEntity userEntity : userEntityList) {
//        组合的key
            String key = VMSystem.getRegionTaskKey(userEntity.getRegionId(), userEntity.getRoleCode());
//        userid
            String value = userEntity.getId().toString();
//        把数据写入Redis的zset中
            redisTemplate.opsForZSet().add(key,value,0);
            redisTemplate.expire(key,1,TimeUnit.DAYS);
        }

    }

    /**
 * 管理员登录
 * @param req
 * @return
 * @throws IOException
 */
private LoginResp adminLogin(LoginReq req) throws IOException {
    LoginResp resp = new LoginResp();
    String code =redisTemplate.boundValueOps(req.getClientToken()).get();
    if(Strings.isNullOrEmpty(code)){
        resp.setMsg("验证码错误");
        return resp;
    }
    if(!req.getCode().equals(code)){
        resp.setMsg("验证码错误");
        return resp;
    }
    QueryWrapper<UserEntity> qw = new QueryWrapper<>();
    qw.lambda()
            .eq(UserEntity::getLoginName,req.getLoginName());
    UserEntity userEntity = this.getOne(qw);
    if(userEntity == null){
        resp.setMsg("账户名或密码错误");
        return resp;
    }
    //验证密码
    boolean loginSuccess = BCrypt.checkpw(req.getPassword(),userEntity.getPassword());
    if(!loginSuccess){
        resp.setMsg("账户名或密码错误");
        return resp;
    }
    //生成token，并存入返回对象
    return okResp(userEntity,VMSystem.LOGIN_ADMIN);
  }

   /**
 * 登录成功签发token
 * @param userEntity
 * @param loginType
 * @return
 */
private LoginResp okResp(UserEntity userEntity,Integer loginType ) throws IOException {
    LoginResp resp = new LoginResp();
    resp.setSuccess(true);
    resp.setRoleCode(userEntity.getRoleCode());
    resp.setUserName(userEntity.getUserName());
    resp.setUserId(userEntity.getId());
    resp.setRegionId(userEntity.getRegionId().toString());
    resp.setMsg("登录成功");
    TokenObject tokenObject = new TokenObject();
    tokenObject.setUserId(userEntity.getId());
    tokenObject.setMobile(userEntity.getMobile());
    tokenObject.setLoginType(loginType);
    String token = JWTUtil.createJWTByObj(tokenObject);
    resp.setToken(token);
    return resp;
}


}
